<?php namespace Remix;

use \Closure;
/**
 * 路由层 暴露的接口给使用者  真正调度的应该是dispater类
 */
class Route
{
    /**
     * 解析的uri
     *
     * @var string
     */
    public $uri;

    /**
     * 请求方法
     *
     * @var string
     */
    public $method;

    /**
     * 当前route使用的controller
     *
     * @var string
     */
    public $controller;

    /**
     * The name of the controller action used by the route.
     *
     * @var string
     */
    public $controller_action;

    /**
     * The action that is assigned to the route.
     *
     * @var mixed
     */
    public $action;

    /**
     * 传入的参数
     *
     * @var array
     */
    public $parameters;

    public function __construct($method, $uri, $action, $parameters = array()) {
        $this->method = $method;
        $this->uri = $uri;
        $this->action = $action;
        $this->parameters($action, $parameters);
    }

    /**
     * 设置参数
     *
     * @param  array   $action
     * @param  array   $parameters
     * @return void
     */
    protected function parameters($action, $parameters)
    {
        $defaults = (array) array_get($action, 'defaults');

        // If there are less parameters than wildcards, we will figure out how
        // many parameters we need to inject from the array of defaults and
        // merge them into the main array for the route.
        if (count($defaults) > count($parameters))
        {
            $defaults = array_slice($defaults, count($parameters));

            $parameters = array_merge($parameters, $defaults);
        }

        $this->parameters = $parameters;
    }

    /**
     * 调用路由的方法
     */
    public function call()
    {
        //todo 加入before_filter

        $response = $this->response();
    
        $response = Response::prepare($response);

        //todo 加入after_filter

        return $response;
    }


    /**
     *
     * 调用route action 返回响应 这里不会执行任何的filter方法
     *
     * @return mixed
     */
    public function response()
    {
        // 如果action是一个字符串 意味着是去调用一个controller 直接返回调用结果即可
        $delegate = $this->delegate();
        if ( ! is_null($delegate))
        {
            return Controller::call($delegate, $this->parameters);
        }

        // 如果路由没有进行委托 那么肯定是一个闭包 或者含有闭包的action数组
        // 我们定位到这个闭包 然后调用
        $handler = $this->handler();
        if ( ! is_null($handler))
        {
            return call_user_func_array($handler, $this->parameters);
        }
    }


    /**
     * 获取是否把route委托给了controller 如果没有 则返回null
     * @return string
     */
    protected function delegate()
    {
        return array_get($this->action, 'uses');
    }

    /**
     * 获取执行route的闭包函数
     *
     * @return Closure
     */
    protected function handler()
    {
        $action = $this->action;

        return array_first($this->action, function($key, $value)
        {
            return $value instanceof Closure;
        });
    }





    //=========定义 一系列的restful方法用于注册路由===========
    /**
     *  使用方法
     *　Route::restful(route, action)
     *
     *  # action 参数为闭包 此时需要调用call_user_func执行
     *  比如 Route::get('/', function(){return 'hello';})
     *
     *  # action参数为字符串 此时需要调用controller
     *  比如 Route::get('/', 'someController@someFunction')
     *
     *  # action参数为array, 此时需要区分
     *  name route
     *  Route::get('/', array('as' => 'login', 'uses' => 'demoController@index'))
     */

    /**
     * 注册get方法
     */
    public static function get($route, $action) {
        Dispatcher::register('GET', $route, $action);
    }

    public static function post($route, $action) {
        Dispatcher::register('POST', $route, $action);
    }

    public static function put($route, $action)
    {
        Dispatcher::register('PUT', $route, $action);
    }

    public static function patch($route, $action)
    {
        Dispatcher::register('PATCH', $route, $action);
    }

    public static function delete($route, $action)
    {
        Dispatcher::register('DELETE', $route, $action);
    }


    //注册一个通用的响应路由
    public static function any($route, $action)
    {
        Dispatcher::register('*', $route, $action);
    }



}